package download;


import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;

import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.TableItem;

import util.Utility;


public class DownloadEngine extends Thread
{

	DownloadInfoBean downloadFileInfoBean = null; 
	TableItem tableItem;
	long[] startPosition; 
	long[] endPosition; 
	long[] oriStartPosition;
	DownloadThread[] downloadThread; 
	long fileLength; 
	boolean isFirstDownload = true; 
	boolean bStop = false; 
	File tmpFile; 
	DataOutputStream output; 


	public DownloadEngine(DownloadInfoBean bean,TableItem newItemTableItem) throws IOException
	{
		downloadFileInfoBean = bean;
		this.tableItem = newItemTableItem;
		
		File sPath = new File(bean.getFilePath());
		if (!sPath.exists() || sPath.isFile())
			sPath.mkdirs();

		tmpFile = new File(bean.getFilePath() + ".down");
		if (tmpFile.exists())
		{
			isFirstDownload = false;
			read_positon();
		}
		else
		{
			startPosition = new long[bean.getThreadNum()];
			endPosition = new long[bean.getThreadNum()];
		}
		
		oriStartPosition = new long[startPosition.length];

	}

	public void run()
	{
		try
		{
			fileLength = getFileLength();
			if (isFirstDownload)
			{
				if (fileLength == -1)
				{
					System.err.println("File Length is not known!");
				}
				else if (fileLength == -2)
				{
					System.err.println("File is not access!");
				}
				else
				{
					for (int i = 0, length = startPosition.length; i < length; i++){
						startPosition[i] = (long) (i * (fileLength / length));
					}
					for (int i = 0, length = endPosition.length; i < length - 1; i++){
						endPosition[i] = startPosition[i + 1];
					}
					endPosition[endPosition.length - 1] = fileLength;
				}
			}
			
			for (int i = 0, length = startPosition.length; i < length; i++){
				oriStartPosition[i] = (long) (i * (fileLength / length));
			}

			
			long speed = 0;
			
			downloadThread = new DownloadThread[startPosition.length];
			for (int i = 0; i < startPosition.length; i++)
			{
				downloadThread[i] = new DownloadThread(downloadFileInfoBean.getSiteURL(), downloadFileInfoBean.getFilePath() + File.separator
						+ downloadFileInfoBean.getFileName(), startPosition[i], endPosition[i], i);
				Utility.log("Thread " + i + " , nStartPos = " + startPosition[i] + ", nEndPos = " + endPosition[i]);
				downloadThread[i].start();
				speed += startPosition[i];
			}

			
			
			boolean breakWhile = false;
			long speed2 = 0;
			while (!bStop)
			{
				write_position();
				Utility.sleep(1000);
				breakWhile = true;
				speed2 = 0;
				long tmp = 0;
				for (int i = 0,length = startPosition.length; i < length; i++)
				{
					if (!downloadThread[i].isDownOver())
					{
						breakWhile = false;

					}
					speed2 += downloadThread[i].getStartPos();
					tmp += downloadThread[i].getStartPos() - oriStartPosition[i];
				}
				if (breakWhile)
					break;
				

				if(tableItem != null)
					Display.getDefault().syncExec(new UpdateTableItem(tableItem, null,(speed2 - speed)/1000 + "kb",tmp * 100 / fileLength + "%"));
				System.out.println(speed2 - speed);
				speed = speed2;
			}

			if(bStop){
				System.err.println("��ͣ�ļ����أ�");
				Display.getDefault().syncExec(new UpdateTableItem(tableItem, null,null,"停止"));
			}
			else{
				tmpFile.delete();


				if(tableItem != null)
					Display.getDefault().syncExec(new UpdateTableItem(tableItem, null,null,"完成"));
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	
	public long getFileLength()
	{
		long fileLength = -1;
		try
		{
			URL url = new URL(downloadFileInfoBean.getSiteURL());
			HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
			httpConnection.setRequestProperty("User-Agent", "NetFox");

			int responseCode = httpConnection.getResponseCode();
			if (responseCode >= 400)
			{
				processErrorCode(responseCode);
				return -2; 
			}

			String sHeader;

			for (int i = 1;; i++)
			{
				sHeader = httpConnection.getHeaderFieldKey(i);
				if (sHeader != null)
				{
					if (sHeader.equals("Content-Length"))
					{
						fileLength = Integer.parseInt(httpConnection.getHeaderField(sHeader));
						break;
					}
				}
				else
					break;
			}
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}

		Utility.log(String.valueOf(fileLength));

		return fileLength;
	}

	
	private void write_position()
	{
		try
		{
			output = new DataOutputStream(new FileOutputStream(tmpFile));
			output.writeInt(startPosition.length);
			for (int i = 0; i < startPosition.length; i++)
			{
				output.writeLong(downloadThread[i].getStartPos());
				output.writeLong(downloadThread[i].getEndPos());
			}
			output.close();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	
	private void read_positon()
	{
		try
		{
			DataInputStream input = new DataInputStream(new FileInputStream(tmpFile));
			int nCount = input.readInt();
			startPosition = new long[nCount];
			endPosition = new long[nCount];
			for (int i = 0; i < startPosition.length; i++)
			{
				startPosition[i] = input.readLong();
				endPosition[i] = input.readLong();
			}
			input.close();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	private void processErrorCode(int nErrorCode)
	{
		System.err.println("Error Code : " + nErrorCode);
	}

	
	public void stopDownload()
	{
		bStop = true;
		for (int i = 0; i < startPosition.length; i++)
			downloadThread[i].threadStop();

	}
	
	protected class UpdateTableItem implements Runnable {
		
		TableItem tableItem;
		String[] s;
		
		public UpdateTableItem(TableItem tableItem, String...s){
			this.tableItem = tableItem;
			this.s = s;
		}
		
		public void run() {
			for(int i=0,len=s.length;i<len;i++){
				if(s[i]!=null){
					tableItem.setText(i,s[i]);
				}
			}
		}
		
	}
	







}
